ostree-remount: mount a tmpfs on /var if necessary so /var is read-write
authorOwen W. Taylor <otaylor@fishsoup.net>
Wed, 9 Jul 2014 23:07:38 +0000 (19:07 -0400)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 10 Jul 2014 01:24:07 +0000 (21:24 -0400)
/var needs to be read-write for a functioning system. Various
systemd services will fail to start if /var is read-only. After we
remount /var (or if we skip remounting /var because / is read-only),
if /var is still readonly, mount a tmpfs file system on /var.

While this isn't strictly part of ostree, keeping it here makes sense
because it keeps twiddling around with the /var mount in one place
for easier coordination and maintenance. This will likely need updating
if systemd gains better support for a readonly root filesystem.

https://bugzilla.gnome.org/show_bug.cgi?id=732979

src/switchroot/ostree-remount.c

index 84d9359c13c19ccf0a2a6cc0e1af11452e8bf4f4..4af7eeb22b67fdfd194232cf53ef461215cb39fe 100644 (file)
 
 #include "ostree-mount-util.h"
 
-int
-main(int argc, char *argv[])
+static int
+path_is_on_readonly_fs (char *path)
 {
-  const char *remounts[] = { "/sysroot", "/etc", "/home", "/root", "/tmp", "/var", NULL };
-  struct stat stbuf;
-  int i;
   struct statvfs stvfsbuf;
 
-  if (statvfs ("/", &stvfsbuf) == -1)
+  if (statvfs (path, &stvfsbuf) == -1)
     {
-      perror ("statvfs(/): ");
+      perrorv ("statvfs(%s): ", path);
       exit (1);
     }
 
-  if (stvfsbuf.f_flag & ST_RDONLY)
+  return (stvfsbuf.f_flag & ST_RDONLY) != 0;
+}
+
+/* Having a writeable /var is necessary for full system functioning.
+ * If /var isn't writeable, we mount tmpfs over it. While this is
+ * somewhat outside of ostree's scope, having all /var twiddling
+ * in one place will make future maintenance easier.
+ */
+static void
+maybe_mount_tmpfs_on_var (void)
+{
+  if (!path_is_on_readonly_fs ("/var"))
+    return;
+
+  if (umount ("/var") < 0 && errno != EINVAL)
+    {
+      perror ("failed to unmount /var prior to mounting tmpfs, mounting over");
+    }
+
+  if (mount ("tmpfs", "/var", "tmpfs", 0, NULL) < 0)
+    {
+      perror ("failed to mount tmpfs on /var");
+      exit (1);
+    }
+}
+
+int
+main(int argc, char *argv[])
+{
+  const char *remounts[] = { "/sysroot", "/etc", "/home", "/root", "/tmp", "/var", NULL };
+  struct stat stbuf;
+  int i;
+
+  if (path_is_on_readonly_fs ("/"))
     {
       /* If / isn't writable, don't do any remounts; we don't want
        * to clear the readonly flag in that case.
        */
+
+      maybe_mount_tmpfs_on_var ();
+
       exit (0);
     }
 
@@ -81,7 +114,9 @@ main(int argc, char *argv[])
             }
        }
     }
-  
+
+  maybe_mount_tmpfs_on_var ();
+
   exit (0);
 }